package com.lighting.common.feign.search.util;

import com.lighting.common.core.util.JsonUtil;
import com.lighting.common.core.vo.BusinessException;
import com.lighting.common.feign.search.annotation.SearchDocument;
import com.lighting.common.feign.search.annotation.SearchField;
import com.lighting.common.feign.search.annotation.SearchFieldType;
import com.lighting.common.feign.search.constant.SearchConstant;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhanghanjun
 * @date 2022-06-28 18:30
 */
public class SearchUtil {

    public static Map<String, Object> beanToMap(Object o) {
        Map<String, Object> map = JsonUtil.beanToMap(o);
        Map<String, String> properties = SearchConstant.indexProperty.get(getIndexName(o.getClass()));
        if (properties == null || properties.isEmpty()) {
            return map;
        }
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            if (entry.getValue() != null && map.containsKey(entry.getKey())) {
                map.put(entry.getValue(), map.remove(entry.getKey()));
            }
        }
        if (map.containsKey(SearchConstant.FLEX_ATTRS)) {
            Map<String, Object> flexAttrs = (Map<String, Object>) map.get(SearchConstant.FLEX_ATTRS);
            for (Object key : map.keySet()) {
                map.put((String) key, flexAttrs.get(key));
            }
            map.remove(SearchConstant.FLEX_ATTRS);
        }
        return map;
    }

    public static <T> List<T> transform(List<Map> list, Class<T> clazz) {
        Map<String, String> properties = SearchConstant.indexProperty.get(getIndexName(clazz));
        if (properties == null || properties.isEmpty()) {
            return JsonUtil.transform(list, clazz);
        }
        for (Map map : list) {
            for (Map.Entry<String, String> entry : properties.entrySet()) {
                if (entry.getValue() != null) {
                    map.put(entry.getKey(), map.remove(entry.getValue()));
                }
            }
            Map<String, Object> flexAttrs = new HashMap<>();
            for (Object key : map.keySet()) {
                if (!properties.containsKey(key)) {
                    flexAttrs.put((String) key, map.get(key));
                }
            }
            if (!flexAttrs.isEmpty()) {
                map.put(SearchConstant.FLEX_ATTRS, flexAttrs);
            }
        }
        List<T> res = JsonUtil.transform(list, clazz);
        return res;
    }

    public static String getIndexName(Class<?> clazz) {
        SearchDocument document = SearchUtil.getAnnotation(clazz, SearchDocument.class);
        if (document == null || StringUtils.isEmpty(document.indexName())) {
            throw new BusinessException("The indexName is not configured for class " + clazz.getName());
        }
        return document.indexName();
    }

    public static Map<String, Object> getFieldSetting(Class<?> clazz) {
        Map<String, Object> properties = clazz.getSuperclass() != null ? getFieldSetting(clazz.getSuperclass()) : new HashMap<>();
        for (Field field : clazz.getDeclaredFields()) {
            SearchField searchField = field.getAnnotation(SearchField.class);
            if (searchField == null) {
                continue;
            }
            Map<String, Object> property = new HashMap<>();
            property.put(SearchConstant.TYPE, searchField.type().name().toLowerCase());
            if (!StringUtils.isEmpty(searchField.analyzer())) {
                property.put(SearchConstant.ANALYZER, searchField.analyzer());
            }
            if (!StringUtils.isEmpty(searchField.searchAnalyzer())) {
                property.put(SearchConstant.SEARCH_ANALYZER, searchField.searchAnalyzer());
            }
            if (searchField.type().equals(SearchFieldType.Text)) {
                if (StringUtils.isEmpty(searchField.analyzer())) {
                    property.put(SearchConstant.ANALYZER, SearchConstant.IK_MAX_WORD);
                }
                if (StringUtils.isEmpty(searchField.searchAnalyzer())) {
                    property.put(SearchConstant.SEARCH_ANALYZER, SearchConstant.IK_SMART);
                }
                Map<String, Object> keyword = new HashMap<>();
                keyword.put(SearchConstant.TYPE, SearchConstant.KEYWORD);
                Map<String, Object> fields = new HashMap<>();
                fields.put(SearchConstant.KEYWORD, keyword);
                property.put(SearchConstant.FIELDS, fields);
            }
            properties.put(searchField.name(), property);
        }
        return properties;
    }

    public static String[] switchFields(String indexName, String[] forcedFields) {
        Map<String, String> properties = SearchConstant.indexProperty.get(indexName);
        if (forcedFields == null || properties == null || properties.isEmpty()) {
            return forcedFields;
        }
        for (int i = 0; i < forcedFields.length; i++) {
            if (properties.get(forcedFields[i]) != null) {
                forcedFields[i] = properties.get(forcedFields[i]);
            }
        }
        return forcedFields;
    }

    public static <T extends Annotation> T getAnnotation(Class<?> clazz, Class<T> a) {
        if (clazz == null) {
            return null;
        }
        T t = clazz.getAnnotation(a);
        if (t != null) {
            return t;
        }
        return getAnnotation(clazz.getSuperclass(), a);
    }
}
